/*
 * @Author: LVGRAPE
 * @Date: 2023-09-05 09:10:42
 * @LastEditTime: 2024-04-24 17:32:10
 * @LastEditors: lvgrape lvgrape@outlook.com
 * @Description:
 * @FilePath: \ZINO_FC_V4\ZINO\hardware\rgb\drv_pwm_dma.c
 * 可以输入预定的版权声明、个性签名、空行等
 */

#include <rtthread.h>
#include "at32f415_tmr.h"
#include "zino.h"
#include <stdlib.h>
#include "pin.h"

#define DBG_TAG "rgb"
#define DBG_LVL DBG_ERROR
#include <rtdbg.h>

#define RGB_COUNT 5
#define DUMMY_PEROID 80 //NOTE pwm输出时第一个波形不正常，需要空几个周期，80*1us
#define RGB_BIT_COUNT (RGB_COUNT*8*3 + DUMMY_PEROID) //
#define RGB_PWM_FRQ 1000000 //800~1100kHz
uint16_t timer_period = 0;
uint8_t rgb_bits_buffer[RGB_BIT_COUNT] = { 0 };
uint8_t rgb_color_buffer[RGB_COUNT * 3];
uint8_t Hv, Lv;
void byte2bits(uint8_t _byte, uint8_t* bits)
{
    for (uint8_t i = 0; i < 8; i++)
    {
        bits[i] = (_byte & 0x80) ? Hv : Lv;
        _byte <<= 1;
    }
}

void rgb_bits_buffer_update(uint8_t* rgb_colors)
{
    // rt_memset(rgb_bits_buffer, 1, sizeof(rgb_bits_buffer));
    LOG_D("rgb_bits_buffer_update:\n");
    for (uint8_t i = 0;i < RGB_COUNT * 3;i++)
    {
        byte2bits(rgb_colors[i], &rgb_bits_buffer[i * 8 + DUMMY_PEROID]);
    }
    for (uint8_t i = 0;i < RGB_BIT_COUNT;i++)
    {
        if (i % 8 == 0) LOG_D("%02d:\n", i / 8);
        LOG_D("%02X ", rgb_bits_buffer[i]);
    }
    LOG_D("\n");
}

int at32_tmr_pwm_dma_init(void)
{
    gpio_init_type gpio_init_struct = { 0 };
    tmr_output_config_type tmr_output_struct;
    dma_init_type dma_init_struct = { 0 };
    crm_clocks_freq_type crm_clocks_freq_struct = { 0 };

    /* get system clock */
    crm_clocks_freq_get(&crm_clocks_freq_struct);
    /* enable tmr1/gpioa/gpiob/dma clock */
    crm_periph_clock_enable(CRM_TMR2_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);

    /* timer2 output pin Configuration */

    gpio_init_struct.gpio_pins = GPIO_PINS_11;
    gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init(GPIOB, &gpio_init_struct);

    gpio_pin_remap_config(TMR2_GMUX_011, TRUE);
    /* tmr1 dma transfer example
    tmr1clk = system_core_clock, prescaler = 0, tmr1 counter clock = system_core_clock

    the objective is to configure tmr1 channel 3 to generate complementary pwm
    signal with a frequency equal to 17.57 khz:
       - tmr1_period = (system_core_clock / 17570) - 1
    and a variable duty cycle that is changed by the dma after a specific number of
    update dma request.

    the number of this repetitive requests is defined by the tmr1 repetition counter,
    each 3 update requests, the tmr1 channel 3 duty cycle changes to the next new
    value defined by the src_buffer. */

    /* compute the value to be set in arr regiter to generate signal frequency at Frq khz */
    timer_period = (crm_clocks_freq_struct.sclk_freq / RGB_PWM_FRQ) - 1;
    /* compute c1dt value to generate a duty cycle at 60% == 600ns */
    Hv = (uint16_t)(((uint32_t)7 * (timer_period - 1)) / 10);//1 0.6us
    /* compute c1dt value to generate a duty cycle at 60% == 600ns*/
    Lv = (uint16_t)(((uint32_t)3 * (timer_period - 1)) / 10);//0 0.3us

    LOG_D("T:%d Hv:0x%02X Lv:%02X\n", timer_period, Hv, Lv);

    tmr_base_init(TMR2, timer_period, 0);
    tmr_cnt_dir_set(TMR2, TMR_COUNT_UP);

    /* channel 3 configuration in output mode */
    tmr_output_default_para_init(&tmr_output_struct);
    tmr_output_struct.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_B;
    tmr_output_struct.oc_output_state = TRUE;
    tmr_output_struct.oc_polarity = TMR_OUTPUT_ACTIVE_LOW;
    tmr_output_struct.oc_idle_state = TRUE;
    tmr_output_struct.occ_output_state = FALSE;
    tmr_output_struct.occ_polarity = TMR_OUTPUT_ACTIVE_LOW;
    tmr_output_struct.occ_idle_state = FALSE;
    /* channel 3 */
    tmr_output_channel_config(TMR2, TMR_SELECT_CHANNEL_4, &tmr_output_struct);

    // tmr_dma_control_config(TMR2, TMR_DMA_TRANSFER_8BYTES, TMR_PR_ADDRESS);


    /* dma config for tmr1 overflow dma request */
    /* dma1 channel5 configuration */
    dma_reset(DMA1_CHANNEL2);
    dma_init_struct.buffer_size = RGB_BIT_COUNT;
    dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_base_addr = (uint32_t)rgb_bits_buffer;
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_base_addr = (uint32_t) & (TMR2->c4dt);
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_WORD;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_VERY_HIGH;
    dma_init_struct.loop_mode_enable = FALSE;
    dma_init(DMA1_CHANNEL2, &dma_init_struct);

    dma_interrupt_enable(DMA1_CHANNEL2, DMA_FDT_INT, TRUE);
    nvic_irq_enable(DMA1_Channel2_IRQn, 2, 2);
    // rt_kprintf("at32_tmr_pwm_dma_init \n");

    /* enable tmr1 overflow dma request */
    /* output enable */
    /* enable tmr1 */
    // tmr_channel_value_set(TMR2, TMR_SELECT_CHANNEL_4, 59);
    tmr_dma_request_enable(TMR2, TMR_OVERFLOW_DMA_REQUEST, TRUE);
    dma_channel_enable(DMA1_CHANNEL2, TRUE);

    tmr_channel_value_set(TMR2, TMR_SELECT_CHANNEL_4, 0);
    // tmr_channel_value_set(TMR2, TMR_SELECT_CHANNEL_4, rgb_bits_buffer[0]);
    tmr_counter_value_set(TMR2, 0);
    tmr_output_enable(TMR2, TRUE);
    tmr_counter_enable(TMR2, TRUE);

    zino_pwr_ctrl(PWR_CTRL_5V_ON);
    return RT_EOK;
}
void DMA1_Channel2_IRQHandler()
{
    // rt_pin_write(27,PIN_LOW);
    /* enter interrupt */
    rt_interrupt_enter();
    if (dma_flag_get(DMA1_FDT2_FLAG) != RESET)
    {
        dma_channel_enable(DMA1_CHANNEL2, FALSE);
        tmr_output_enable(TMR2, FALSE);
        dma_flag_clear(DMA1_FDT2_FLAG);
        tmr_counter_enable(TMR2, FALSE);
        tmr_dma_request_enable(TMR2, TMR_OVERFLOW_DMA_REQUEST, FALSE);
        rt_pin_write(27, PIN_LOW);

        LOG_D(" \t dma1 channel tx complete %d\n", dma_data_number_get(DMA1_CHANNEL2));
    }
    /* leave interrupt */
    rt_interrupt_leave();
}
void rgb_show()
{
    rgb_bits_buffer_update(rgb_color_buffer);

    // dma_data_number_set(DMA1_CHANNEL7, RGB_BIT_COUNT);

    // dma_channel_enable(DMA1_CHANNEL7, TRUE);
    // /* output enable */
    // tmr_output_enable(TMR2, TRUE);
    // /* enable tmr1 */
    // tmr_counter_enable(TMR2, TRUE);
    // tmr_dma_request_enable(TMR2, TMR_C4_DMA_REQUEST, TRUE);
    // dma_interrupt_enable(DMA1_CHANNEL7, DMA_FDT_INT, TRUE);
    // nvic_irq_enable(DMA1_Channel7_IRQn, 2, 2);
    rt_pin_write(27, PIN_LOW);
    at32_tmr_pwm_dma_init();
}
void rgb_set_color(uint8_t index, uint8_t r, uint8_t g, uint8_t b)
{
    if (index >= RGB_COUNT) return;
   // for(int index=0;index<=5;index++){
    rgb_color_buffer[index * 3 + 0] = g;
    rgb_color_buffer[index * 3 + 1] = r;
    rgb_color_buffer[index * 3 + 2] = b;
  //  }

}
long rgb_set(int argc, char** argv)
{

    if (argc == 5)
    {
        int i, r, g, b;
        i = atoi(argv[1]);
        r = atoi(argv[2]);
        g = atoi(argv[3]);
        b = atoi(argv[4]);
        if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255)
        {
            zino_pwr_ctrl(PWR_CTRL_5V_ON);
            rgb_set_color(i, r, g, b);
            rt_kprintf("set color_%d %d %d %d\n", i, r, g, b);
            rgb_show();
        }
    }
    else
    {
        rt_kprintf("Usage:\n");
        rt_kprintf("\trgb_set 1 255 255 255\n");
    }
    return RT_EOK;
}
// ZINO_BOARD_EXPORT(at32_tmr_pwm_dma_init);
// MSH_CMD_EXPORT(rgb_set, rgb set);